﻿using System;
using System.Collections.Generic;
using System.Linq;
using QDT.Common;
using QDT.Core;
using QDT.Core.Deals;
using QDT.Core.Members;
using QDT.Core.Projects;
using QDT.P2B.Domain.Config;
using QDT.P2B.Domain.Messages;
using QDT.Services.Projects;

namespace QDT.Services.Deals {
    public class DealService : ServiceBase, IDealService {
        #region Implementation of IBidService

        private static readonly object _asnyLock = new object();

        public Credit Bid(int userid, int projectid, decimal money, bool isAuto)
        {
            lock (_asnyLock) {
                User user = DbProvider.D<User>().Where(x => x.ID == userid && x.IsEffect && !x.IsDelete).ToList().FirstOrDefault();
                if (user == null) throw new Exception("用户不存在或者已经被删除");
                Project project = DbProvider.D<Project>().FirstOrDefault(x => x.ID == projectid && x.IsEffect && !x.IsDelete);
                if (project == null) throw new Exception("项目不存在");

                DbProvider.Refresh(user.UserAccount);
                DbProvider.Refresh(project);
                return Bid(user, project, money, isAuto);
            }
        }

        /// <summary>
        /// 还款
        /// </summary>
        /// <param name="projectId">贷款ID</param>
        /// <param name="stage">还款第几期，如果设置0或者不填写，默认还当前最新一期</param>
        /// <param name="adminId">管理员ID</param>
        public void Refund(int projectId, int stage = 0, int adminId = 0) {

            var project = DbProvider.GetByID<Project>(projectId);

            if (project == null) throw new RefundException(RefundException.NotExistProject);

            if (project.Status != ProjectStatus.Repaying) throw new RefundException(RefundException.InvalidProjectStatus, project);

            if (!project.NextRepayTime.HasValue || project.NextRepayTime.Value.Date > DateTime.Now) throw new RefundException(RefundException.InvalidProjectStatus, project); 

            List<DebtorRepayment> records = DbProvider.D<DebtorRepayment>().Where(x => x.ProjectID == project.ID).ToList();

            IRepayStrategyFactory factory = new RepayStrategyFactory();
            //获得还款策略
            IRepayStrategy strategy = factory.GetRepayStrategy(project);

            RepaymentScheme scheme = strategy.GetRepayTableForProject(records);

            if (scheme.IsCompleted) throw new RefundException(RefundException.HasReplsyCompleted, project);

            RepaymentStage curStage = scheme.CurrentStage;

            //获得借款人
            var borrower = DbProvider.GetByID<User>(project.UserID);

            //金额不足
            if (borrower.UserAccount.Money < curStage.Ammount) throw new RefundException(RefundException.NotEnoughMoney, project);

            //扣除金额
            var log=borrower.Transaction(UserTransLog.TradeType.RecoverInterest, -curStage.Ammount, "", "{0},第{1}期,偿还{2}".FormatWith(project.Name, curStage.Stage, curStage.Remark));

            DateTime trueRepayTine = DateTime.Now;

            var dealofrepay = new DebtorRepayment(project, borrower, curStage.Ammount, curStage.Principal) {
                                                                                                               Stage = curStage.Stage,
                                                                                                               RepayTime = curStage.Time,
                                                                                                               TrueRepayTime = trueRepayTine
                                                                                                           };
            project.LastRepayTime = trueRepayTine;
            project.CurrentStage = curStage.Stage;
            project.TotalStage = scheme.Stages.Count;
            project.RepayMoney = scheme.RepayMoney + curStage.Ammount;

            if(curStage.IsLast) {
                //还款结束
                project.SetRepaidStatus();
                project.NextRepayTime = null;
            }else{
                project.NextRepayTime = scheme[curStage.Stage + 1].Time;
            }

            DbProvider.Add(dealofrepay);
            DbProvider.Add(log);


            //开始回款给用户

            #region "回款给债权人"
            //获得所有的债权人
            IQueryable<Credit> credits = DbProvider.D<Credit>().Where(x => x.ProjectID == projectId);

            foreach (Credit credit in credits) {
                
                if (!credit.IsEffect) continue;

                RepaymentScheme userScheme = strategy.GetCreditRepaymenScheme(credit);

                RepaymentStage userStage = userScheme[curStage.Stage];

                if (userStage.IsRepay) continue;

                //如果回款记录不存在，给用户回款
                var creditRecord = new CreditRepayment {
                                                             CreditId = credit.ID,
                                                             Stage = userStage.Stage,
                                                             RepayMoney = userStage.Ammount,
                                                             RepayTime = userStage.Time,
                                                             TrueRepayTime = trueRepayTine
                                                         };

                credit.LastRepayTime = creditRecord.TrueRepayTime;
                credit.RepayEarning = userScheme.RepayInterest + userStage.Interest;
                credit.RepayPrincipal = userScheme.RepayPrincipal + userStage.Principal;
                credit.WaitRepayEarning = userScheme.WaitRepayInterest - userStage.Interest;
                credit.WaitRepayPrincipal = userScheme.WaitRepayPrincipal - userStage.Principal;
                credit.CurrentStage = userStage.Stage;
                credit.TotalStage = userScheme.Stages.Count;

                if (userStage.IsLast)
                {
                    credit.NextRepayTime = null;
                    credit.Status = CreditStatus.Completed;
                }
                else
                {
                    credit.NextRepayTime = userScheme[userStage.Stage + 1].Time;
                }

                var user = DbProvider.GetByID<User>(credit.UserID);

                //加钱
                var remark = "{0},第{1}期,偿还{2}".FormatWith(project.Name, curStage.Stage, curStage.Remark);

                var userLog = user.Transaction(userStage.RepayType == 1 ? UserTransLog.TradeType.RecoverInterest : UserTransLog.TradeType.RecoverPrincipal, creditRecord.RepayMoney, borrower.UserName, remark);
                
                //线下和路人不发短信
                if (user.MobilePassed && SettingManager.Get<MessageConfig>().SmsOpen && user.GroupID != 1 && user.GroupID != 5 && user.GroupID != 6)
                {
                    MsgQueue msg = new MsgQueueFactory().CreateRepayMsg(user, creditRecord.RepayMoney, projectId);
                    if(msg!=null){
                        DbProvider.Add(msg);
                    }
                }

                DbProvider.Add(userLog);
                DbProvider.Add(creditRecord);

            }

            #endregion

            DbProvider.SaveChanges();
        }

        public void Bad(int projectId)
        {
            var project = DbProvider.GetByID<Project>(projectId);
            if (project == null) throw new Exception("无效Id");

            project.SetBadStatus();

            var credits = DbProvider.D<Credit>().Where(x => x.ProjectID == projectId);

            foreach (var credit in credits)
            {
                var user = DbProvider.GetByID<User>(credit.UserID);
                string msg = "项目{0}流标".FormatWith(project.Name);
                var log = user.UnfreezeMoney(UserTransLog.TradeType.InvestFaild, credit.Money, "", msg);
                DbProvider.Add(log);
                credit.Status = CreditStatus.Bad;
            }
            try
            {
                DbProvider.SaveChanges();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        /// <summary>
        /// 获得Project的还款信息表
        /// </summary>
        /// <param name="projectId">项目ID</param>
        /// <returns></returns>
        public RepaymentScheme GetRepaymentScheme(int projectId) {
            var project = DbProvider.GetByID<Project>(projectId);

            if (project.Status != ProjectStatus.Repaying && project.Status != ProjectStatus.Repaid) throw new RefundException(RefundException.InvalidProjectStatus, project);

            List<DebtorRepayment> records = DbProvider.D<DebtorRepayment>().Where(x => x.ProjectID == projectId).ToList();

            IRepayStrategyFactory factory = new RepayStrategyFactory();

            return factory.GetRepayStrategy(project).GetRepayTableForProject(records);
        }

        /// <summary>
        /// 投资用户投资项目操作方法
        /// </summary>
        /// <param name="user">投资人</param>
        /// <param name="project">项目</param>
        /// <param name="money">投资金额</param>
        /// <param name="isAuto">是否自动投资</param>
        /// <returns></returns>
        public Credit Bid(User user, Project project, decimal money, bool isAuto)
        {
            ValidateBid(user, project, money);
            user.UserAccount.CurrentChargeMoney -= money;

            var credit = new Credit
            {
                ProjectID = project.ID,
                UserID = user.ID,
                UserName = user.UserName,
                Money = money,
                BuyMoney = money,
                CreateTime = DateTime.Now,
                Type = InvestType.Project,
                Status = CreditStatus.Biding,
                IsAuto = isAuto
            };

            project.LoadMoney += money;

            if (project.NeedMoney == 0)
            {
                //如果项目已经满了，更新状态
                project.SetFullStatus();

                foreach (var ct in DbProvider.D<Credit>().Where(x => x.ProjectID == project.ID).ToList())
                {
                    ct.Status = CreditStatus.Full;
                }
            }

            //还需要发送短信，邮件等

            //冻结资金
            string msg = "投资了{0}".FormatWith(project.Name, isAuto ? "（自动）" : "");
            var userLog = user.FreezeMoney(UserTransLog.TradeType.InvestToLock, money, "", msg);

            DbProvider.Add(credit);
            DbProvider.Add(userLog);

            DbProvider.SaveChanges();

            return credit;
        }

        #endregion

        private void ValidateBid(User user, Project project, decimal money) {
            //投资金额不能是负数和0
            if (money <= 0) throw new BidException(BidException.NotNegativeOrZero, user, project);
            //项目状态是否处于进行中
            if (project.IsDelete || !project.IsEffect || project.Status != ProjectStatus.Progress) throw new BidException(BidException.InVaildProjectStatus, user, project);
            //项目可投余额
            if (project.NeedMoney < money) throw new BidException(BidException.ProjectNeedOutOfRange, user, project);
            //用户余额
            if (user.UserAccount.Money < money) throw new BidException(BidException.UserLackOfBalance, user, project);
            //是否是有效的投资人
            if (!user.IsLender || user.IsDelete || !user.IsEffect) throw new BidException(BidException.InvaildLender, user, project);
            //项目最低投资金额
            if (project.MinLoanMoney > money && project.NeedMoney > project.MinLoanMoney) throw new BidException(BidException.MinLoanOutOfRange, user, project);
            if (project.StartTime > DateTime.Now) throw new BidException("未到开始时间，不能投标 !");
        }



    }
}